/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-13
 * V4.0
 */
package com.jphenix.webserver.instancea;

import com.jphenix.share.bean.instancea.FilesUtil;
import com.jphenix.share.lang.SEnumeration;
import com.jphenix.share.lang.SString;
import com.jphenix.standard.beans.IFilesUtil;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.exceptions.EmptyException;
import com.jphenix.ver.PhenixVer;
import com.jphenix.webserver.filter.FilterConfigImpl;
import com.jphenix.webserver.interfaceclass.IGlobalVar;
import com.jphenix.webserver.interfaceclass.ILog;
import com.jphenix.webserver.interfaceclass.IServeParameter;
import com.jphenix.webserver.servlet.ASuperServlet;
import com.jphenix.webserver.servlet.FileServlet;
import com.jphenix.webserver.servlet.ServletInfoBean;
import com.jphenix.webserver.session.HttpSessionEvent;

import javax.servlet.*;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionListener;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.*;
import java.util.*;

/*
 * 嵌入式Web服务器
 * 主要用来开发和调试网站程序
 * 或用于小型网站或应急使用
 */

/**
 * 服务入口类
 * 
 * 
 * 2018-05-22 改为，如果不设置绑定网卡IP地址，则允许响应所有本机网卡地址
 * 2018-11-02 完善了输入错的URL时，后台留下的日志，便于找到问题
 * 2019-01-17 在终止服务程序钩子中增加了提示日志
 * 2019-09-17 整理了代码格式
 * 2021-03-17 适配tomcat9中的 servlet-api.jar
 * 
 * com.jphenix.webserver.instancea.Serve
 * @author 刘虻
 * 2006-9-15上午12:08:44
 */
@ClassInfo({"2021-03-17 20:54","服务入口类"})
public class Serve implements ServletContext, RequestDispatcher, Serializable {
	
	/**
	 * 版本标识
	 */
	private static final long serialVersionUID = -8257580690642041677L;
 
	private transient boolean            running = true;   //服务是否运行
	private transient PathTreeDictionary registry;         //Servlet 容器
	private transient KeepAliveCleaner   keepAliveCleaner; //连接清除类
	private transient ThreadGroup        serverThreads;    //服务处理线程
	private transient ThreadManager      threadManager;    //线程池
	private transient ServerSocket       serverSocket;     //服务器端口
	private transient ServerSocket       sslServerSocket;  //SSL服务器端口
	private transient Thread             ssclThread;       //会话处理线程
	
	private String   hostName;                  //服务器名
	private String   bindAddress        = null; //绑定地址
	private String   keepAliveHdrParams = null; //http头keepAlive参数
	private String   serverName         = null; //服务器名
	private String   sessionCookieName  = null; //会话主键名
	private String   contextPath        = null; //虚拟路径　（目前该服务器只能有一个虚拟路径）
	private String[] welcomePages       = null; // 默认显示文件数组
	
	private int   sessionTimeOut    = 0; //会话超时时间
	private int   contextPathLength = 0; //虚拟路径长度
	private int   timeoutKeepAlive;      //浏览器与服务器连接超时时间
	private int   maxAliveConnUse;       //浏览器与服务器连接数
	private int  uniqer;                //会话主键序列(防止会话主键重复
	
	private long startTime          = System.currentTimeMillis(); //启动开始时间
	
	private HttpSessionContextImpl         sessions;                   //会话上下文
	private Hashtable<String,Object>       attributes          = null; //上下文属性容器
	private Thread                         sdHook              = null; //程序关闭钩子
	private IServeParameter                serveParameter      = null; //服务参数处理类
	private ILog                           log                 = null; //日志处理类
	private ArrayList<Filter>              filterList          = null; //过滤器序列
	private ArrayList<HttpSessionListener> sessionListenerList = null; //会话监听器序列
	private ArrayList<Servlet>             noUseServletList    = null; //获取只加载不使用的Servlet
	private IFilesUtil                     filesUtil           = null; //文件处理工具
	
	
	//内部web服务器：比如生产环境运行着tomcat，但是像脚本操作，文件操作等高风险
	//动作，不能开放到外网访问，就需要项目另监听一个端口，专门用来内部操作。
	protected boolean isNativeServ = false; //是否为内部Web服务器
	private   boolean keepAlive;            //浏览器与服务器是否保持连接
	
	/**
	 * 构造参数
	 * @author 刘虻
	 * 2007-9-29下午04:54:24
	 */
	public Serve() {
		super();
	}
	
	/**
	 * 执行监听线程
	 * @author 刘虻
	 * 2008-7-8下午04:06:28
	 */
	protected class ListenAcceptThread extends Thread {
		
		protected ServerSocket sSocket = null; //服务器Socket
		protected Serve serve = null; //服务类
		
		protected int returnValue = 0; //返回值
		
		/**
		 * 构造函数
		 * 2008-7-8下午04:06:50
		 */
		public ListenAcceptThread(ServerSocket sSocket,Serve serve) {
			super("Serv-ListenAcceptThread");
			this.sSocket = sSocket;
			this.serve = serve;
		}
		
		/**
		 * 获取返回值
		 * @author 刘虻
		 * 2008-7-8下午04:09:48
		 * @return 返回值
		 */
		public int getReturnValue() {
			return returnValue;
		}
		
		/**
		 * 覆盖方法
		 * @author 刘虻
		 * 2008-7-8下午04:06:59
		 */
		@Override
        public void run() {
			try {
				while (running) {
					try {
						//获取浏览器与服务器连接Socket
						Socket socket = sSocket.accept();
						
						//在ServeConnection的构造函数中启动了线程管理
						new ServeConnection(socket, serve);
					} catch (IOException e) {
						log("Accept: " + e);
					} catch (SecurityException se) {
						log("Illegal access: " + se);
					}
				}
			} catch (Throwable t) {
				log("Unhandled exception: " + t + ", server is terminating.", t);
				returnValue = -1;
				return;
			} finally {
				try {
					if (sSocket != null) {
                        sSocket.close();
                    }
				} catch (IOException e) {
				}
			}
		}
	}
	
	/**
	 * 启动入口
	 * 
     * 当第一个参数为 1 时，为直传参数模式
     * 在该模式下，第二个参数为监听端口
     * 第三个传入参数为虚拟路径
     * 直传参数模式只支持者两个参数
     * 
	 * @author 刘虻
	 * 2007-9-29下午04:38:45
	 * @param args 导入参数
	 */
	public static void main(String[] args) {
		
		//构造服务类实例
		Serve serve = new Serve();
		
		//启动服务
		serve.startup(args);
	}

	/**
	 * 获取服务参数处理类实例
	 * @author 刘虻
	 * 2007-9-29下午04:58:47
	 * @return 服务参数处理类实例
	 */
	public IServeParameter getServeParameter() {
		if (serveParameter==null) {
			serveParameter = new ServeParameter(this);
		}
		return serveParameter;
	}
	
	
	/**
	 * 获取文件处理工具
	 * @author 刘虻
	 * 2008-2-20下午01:55:35
	 * @return 文件处理工具
	 */
	public IFilesUtil getFilesUtil() {
		if (filesUtil==null) {
			filesUtil = FilesUtil.newInstance();
		}
		return filesUtil;
	}
	
	/**
	 * 设置文件处理工具
	 * @author 刘虻
	 * 2009-11-11上午10:35:05
	 * @param filesUtil 文件处理工具
	 */
	public void setFilesUtil(IFilesUtil filesUtil) {
		this.filesUtil = filesUtil;
	}
	
	/**
	 * 获取系统日志流
	 * @author 刘虻
	 * 2006-9-15上午11:22:18
	 * @param argumentMap 导入参数容器 from=givenpath;dir=realpath
	 * @return 系统日志流
	 */
	public void initLog() {
		//构建日志类实例
		log = new Log();
		//是否输出普通日志
		log.setOutLog(getServeParameter().getArgumentBoolean(IGlobalVar.ARG_OUT_SERVLOG));
		//设置日志默认编码格式
		log.setLogEncoding(System.getProperty(IGlobalVar.DEF_LOGENCODING));
		//设置工作路径
		log.setWorkPath(getServeParameter().getServletBasePath()+"/logs");
		//设置输出日志流
		log.setLogStream(System.out);
	}
	
	
	
	/**
	 * 执行初始化
	 * @author 刘虻
	 * 2007-9-30下午02:43:33
	 */
	protected void initialize(String[] args) throws Exception {

		//初始化导入参数
		getServeParameter().initProp(args); 
		
		//初始化日志类
		initLog();
		
		if (!getServeParameter().getArgumentBoolean("nover")) {
			PhenixVer.printVERShowInfo(); //显示版本信息
		}
		
		System.out.println(">> [" + new Date() + "] Load Server Config File:["+getServeParameter().getConfigFilePath()+"]");
		System.out.println(">>Set Base Web Path:["+getServeParameter().getWebBasePath()+"]");
		System.out.println(">>Set Servlet Base Path:["+getServeParameter().getServletBasePath()+"]");
		System.out.println(">>Set Servlet Context Path:["+getServeParameter().getArgumentMap().get("context-path")+"]");

		registry = new PathTreeDictionary();
		attributes = new Hashtable<String, Object>();
		
		//获取虚拟路径
		contextPath = 
			getServeParameter()
				.getArgumentString(IGlobalVar.ARG_CONTEXT_PATH);
		if ("/".equals(contextPath)) {
			contextPath = "";
		}
		//设置虚拟路径长度
		contextPathLength = contextPath.length();
		
		//构建线程池组
		serverThreads = new ThreadGroup("Phenix WebServer threads");
		
		//构建线程管理类
		threadManager = new ThreadManager();
		//最大处理线程数
		int maxThreadCount = 
			getServeParameter().getArgumentInt(IGlobalVar.ARG_MAX_EXECUTE_THREAD_COUNT);
		if (maxThreadCount<1) {
			maxThreadCount = 10;
		}
		threadManager.setMaxThreadCount(maxThreadCount);
		
		threadManager.start(); //启动线程管理
		
		//会话主键名
		sessionCookieName = 
			getServeParameter()
				.getArgumentString(IGlobalVar.ARG_SESSION_COOKIE_NAME);
		if (sessionCookieName.length()==0) {
			sessionCookieName = IGlobalVar.DEF_SESSION_COOKIE_NAME;
		}
		keepAlive = 
			getServeParameter()
				.getArgumentBoolean(IGlobalVar.ARG_KEEPALIVE);
		//浏览器与服务器通信保持时间(秒)
		int timeoutKeepAliveSec = 
				getServeParameter()
					.getArgumentInt(IGlobalVar.ARG_KEEPALIVE_TIMEOUT);
		if (timeoutKeepAliveSec<1) {
			timeoutKeepAliveSec = 30;
		}
		timeoutKeepAlive = timeoutKeepAliveSec * 1000;
		
		//并发线程数
		maxAliveConnUse = 
			getServeParameter()
				.getArgumentInt(IGlobalVar.ARG_MAX_CONN_USE);
		if (maxAliveConnUse<1) {
			maxAliveConnUse = IGlobalVar.DEF_MAX_CONN_USE;
		}
		//处理http头keepAlive参数
		keepAliveHdrParams = 
			"timeout="+timeoutKeepAliveSec+", max=" + maxAliveConnUse;

		//获取会话超时时间
		sessionTimeOut = 
			getServeParameter().getArgumentInt(IGlobalVar.ARG_SESSION_TIMEOUT);
		if (sessionTimeOut<1) {
			sessionTimeOut = IGlobalVar.DEF_SESSION_TIMEOUT;
		}
		//添加关闭钩子
		Runtime.getRuntime().addShutdownHook(
				//构建新的关闭钩子
				sdHook = new Thread(new Runnable() {
					
				/**
				 * 覆盖方法
				 * @author 刘虻
				 * 2007-9-30下午03:27:03
				 */
				@Override
                synchronized public void run() {
					System.err.printf("\n\n\n*******************The Web Serv Has Stoped***********************\n\n\n");
					destroyAllFilter();		//终止所有的过滤器
					destroyAllServlets();	//终止所有的Servlet
				}
			},"ShutDownHook"));
	}


	/**
	 * 启动内部Web服务器
	 * @param port              监听端口
	 * @param contextPath       虚拟路径
	 * @param filter            已经初始化（被外部Servlet容器初始化）后的主过滤器
	 * @throws Exception        异常
	 * 2017年8月31日
	 * @author MBG
	 */
	public void startup(int port,String contextPath,Filter filter) throws Exception {
		

		String[] args = new String[3];
		args[0] = "1";
		args[1] = String.valueOf(port);
		args[2] = contextPath;
		
		//初始化导入参数
		getServeParameter().initProp(args); 
		
		//初始化日志类
		initLog();
		
		registry = new PathTreeDictionary();
		attributes = new Hashtable<String, Object>();
		
		if ("/".equals(contextPath)) {
			contextPath = "";
		}
		this.contextPath = contextPath;
		//设置虚拟路径长度
		contextPathLength = contextPath.length();
		
		//构建线程池组
		serverThreads = new ThreadGroup("Native Web Server threads");
		
		//构建线程管理类
		threadManager = new ThreadManager();
		//最大处理线程数
		int maxThreadCount = 
			getServeParameter().getArgumentInt(IGlobalVar.ARG_MAX_EXECUTE_THREAD_COUNT);
		if (maxThreadCount<1) {
			maxThreadCount = 10;
		}
		threadManager.setMaxThreadCount(maxThreadCount);
		
		threadManager.start(); //启动线程管理
		
		//会话主键名
		sessionCookieName = 
			getServeParameter()
				.getArgumentString(IGlobalVar.ARG_SESSION_COOKIE_NAME);
		if (sessionCookieName.length()==0) {
			sessionCookieName = IGlobalVar.DEF_SESSION_COOKIE_NAME;
		}
		keepAlive = 
			getServeParameter()
				.getArgumentBoolean(IGlobalVar.ARG_KEEPALIVE);
		//浏览器与服务器通信保持时间(秒)
		int timeoutKeepAliveSec = 
				getServeParameter()
					.getArgumentInt(IGlobalVar.ARG_KEEPALIVE_TIMEOUT);
		if (timeoutKeepAliveSec<1) {
			timeoutKeepAliveSec = 30;
		}
		timeoutKeepAlive = timeoutKeepAliveSec * 1000;
		
		//并发线程数
		maxAliveConnUse = 
			getServeParameter()
				.getArgumentInt(IGlobalVar.ARG_MAX_CONN_USE);
		if (maxAliveConnUse<1) {
			maxAliveConnUse = IGlobalVar.DEF_MAX_CONN_USE;
		}
		//处理http头keepAlive参数
		keepAliveHdrParams = 
			"timeout="+timeoutKeepAliveSec+", max=" + maxAliveConnUse;

		//获取会话超时时间
		sessionTimeOut = 
			getServeParameter().getArgumentInt(IGlobalVar.ARG_SESSION_TIMEOUT);
		if (sessionTimeOut<1) {
			sessionTimeOut = IGlobalVar.DEF_SESSION_TIMEOUT;
		}
		
		//添加默认Servlet
		try {
			addDefaultServlets(null);
		} catch (IOException e) {
			log("Problem reading throttles file: " + e, e);
			System.exit(1);
		}
		
		//添加已经初始化后的主过滤器
		getFilterList().add(filter);
		
		
		isNativeServ = true; //标记为内部Web服务

		// And run.
		int code = doServe();
		destroyAllServlets();
		killAliveThreads();
		System.out.println("\n\n16-----------------------------------------------------------------------\nNative Web Server:The Application Has Bean Stoped. Code:["+code+"]\n--------------------------------------------------------------------------------------\n");

	}
	
	
	/**
	 * 执行启动服务
	 * 
     * 当第一个参数为 1 时，为直传参数模式
     * 在该模式下，第二个参数为监听端口
     * 第三个传入参数为虚拟路径
     * 直传参数模式只支持者两个参数
	 * 
	 * @author 刘虻
	 * 2007-9-29下午04:39:42
	 * @param args 导入参数
	 */
	public void startup(String[] args) {
		try {
			initialize(args); //执行初始化
		}catch(EmptyException e0) {
			return;
		}catch(Exception e) {
			e.printStackTrace();
			return;
		}
		
		//私有Servlet配置文件路径
		String throttles = 
			getServeParameter().getArgumentString(IGlobalVar.ARG_THROTTLES);
		if (throttles.length()>0) {
			throttles = 
				getFilesUtil().getAllFilePath(throttles);
		}
		//添加默认Servlet
		try {
			addDefaultServlets(null);
		} catch (IOException e) {
			log("Problem reading throttles file: " + e, e);
			System.out.println("\n\n15-----------------------------------------------------------------------\nThe Application Has Bean Stoped\n--------------------------------------------------------------------------------------\n");
			System.exit(1);
		}
		
		addModule(); //加载Servlet Filter SessionListener
		
		// And run.
		int code = doServe();
		Runtime.getRuntime().removeShutdownHook(sdHook);
		destroyAllServlets();
		killAliveThreads();
		System.out.println("\n\n16-----------------------------------------------------------------------\nThe Application Has Bean Stoped\n--------------------------------------------------------------------------------------\n");
		System.exit(code);
	}

	/**
	 * 加载Servlet Filter SessionListener
	 * @author 刘虻
	 * 2008-6-28下午07:00:25
	 */
	protected void addModule() {
		//添加Servlet
		for(ServletInfoBean sib:getServeParameter().getServletInfoList()) {
			if (sib==null) {
				continue;
			}
			if (sib.getMappingList().size()>0) {
				for(int j=0;j<sib.getMappingList().size();j++) {
					//增加会话信息类
					addServlet(SString.valueOf(sib.getMappingList().get(j)),sib.getClassPath(),sib.getParaMap());
				}
			}else {
				//加载Servlet
				try {
					//构建Servlet
					Servlet servlet = (Servlet)Class.forName(sib.getClassPath()).newInstance();
					//初始化会话
					servlet.init(new ServeConfig(this, sib.getParaMap(), ""));
					
					//放入容器
					getNoUseServletList().add(servlet);
				}catch(Exception e) {
					e.printStackTrace();
				}
			}
		}
		//添加Filter
		for(ServletInfoBean sib:getServeParameter().getFilterInfoList()) {
			if (sib.getClassPath()!=null && sib.getClassPath().length()>0) {
				try {
					//构建过滤器类实例
					Filter filter = 
						(Filter)Class.forName(sib.getClassPath()).newInstance();
					//构建过滤器配置信息类
					FilterConfigImpl fci = new FilterConfigImpl();
					fci.setParameterMap(sib.getParaMap());
					fci.setFilterName(sib.getName());
					fci.setServletContext(this);
					filter.init(fci);
					getFilterList().add(filter);
				}catch(Exception e) {
					e.printStackTrace();
				}
			}
		}
		
		//添加SessionListener
		for(int i=0;i<getServeParameter().getSessionListenerClassList().size();i++) {
			//获取会话监听器类路径
			String classPath =
					getServeParameter().getSessionListenerClassList().get(i);
			if (classPath==null || classPath.length()<1) {
				continue;
			}
			try {
				getSessionListenerList()
					.add((HttpSessionListener)Class.forName(classPath).newInstance());
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}


	/**
	 * 获取浏览器与服务器是否保持连接
	 * @author 刘虻
	 * 2008-6-28下午06:52:12
	 * @return 浏览器与服务器是否保持连接
	 */
	public boolean isKeepAlive() {
		return keepAlive;
	}

	/**
	 * 获取浏览器与服务器连接超时时间
	 * @author 刘虻
	 * 2008-6-28下午06:52:29
	 * @return 浏览器与服务器连接超时时间
	 */
	public int getKeepAliveDuration() {
		return timeoutKeepAlive;
	}

	/**
	 * 获取http头keepAlive参数
	 * @author 刘虻
	 * 2007-9-30下午03:34:15
	 * @return http头keepAlive参数
	 */
	public String getKeepAliveParamStr() {
		return keepAliveHdrParams;
	}

	/**
	 * 获取并发连接数
	 * @author 刘虻
	 * 2008-6-28下午06:51:02
	 * @return 并发连接数
	 */
	public int getMaxTimesConnectionUse() {
		return maxAliveConnUse;
	}
	
	
	/**
	 * 获取会话超时时间
	 * @author 刘虻
	 * 2007-9-30下午03:31:58
	 * @return 会话超时时间
	 */
	public int getSessionTimeOut() {
		return sessionTimeOut;
	}


	/**
	 * 添加Servlet
	 * @author 刘虻
	 * 2008-6-28下午06:50:32
	 * @param urlPat Servlet名
	 * @param className Servlet 类路径
	 * @return 
	 */
	@Override
    public ServletRegistration.Dynamic addServlet(String urlPat, String className) {
		return addServlet(urlPat, className, null);
	}

	/**
	 * 加载Servlet
	 * @author 刘虻
	 * 2008-6-28下午06:48:07
	 * @param urlPat Servlet名
	 * @param className Servlet 类路径
	 * @param initParams 初始化参数容器
	 */
	public ServletRegistration.Dynamic addServlet(
			String urlPat, String className, Hashtable<String,Object> initParams) {
		// Check if we're allowed to make one of these.
		SecurityManager security = System.getSecurityManager();
		if (security != null) {
			int i = className.lastIndexOf('.');
			if (i > 0) {
				security.checkPackageAccess(className.substring(0, i));
				security.checkPackageDefinition(className.substring(0, i));
			}
		}
		try {
			addServlet(
					urlPat
					, (Servlet)Class.forName(className).newInstance()
					, initParams);
		} catch (ClassNotFoundException e) {
			log("Class not found: " + className);
		} catch (ClassCastException e) {
			log("Class cast problem: " + e.getMessage());
		} catch (InstantiationException e) {
			log("Instantiation problem: " + e.getMessage());
		} catch (IllegalAccessException e) {
			log("Illegal class access: " + e.getMessage());
		} catch (Exception e) {
			log("Unexpected problem creating servlet: " + e, e);
		}
		return null;
	}


	/**
	 * 加载Servlet
	 * @author 刘虻
	 * 2008-6-28下午06:47:03
	 * @param urlPat Servlet 名字
	 * @param servlet Servlet
	 */
	@Override
    public ServletRegistration.Dynamic addServlet(String urlPat, Servlet servlet) {
		return addServlet(urlPat, servlet, null);
	}

	/**
	 * 加载Servlet
	 * @author 刘虻
	 * 2008-6-28下午06:46:17
	 * @param urlPat Servlet 名字
	 * @param servlet Servlet
	 * @param initParams 初始化参数
	 */
	public synchronized ServletRegistration.Dynamic addServlet(
			String urlPat, Servlet servlet, Hashtable<String,Object> initParams) {
		setSuperServlet(servlet); //设置超级Servlet属性
		if (initParams==null) {
			initParams = new Hashtable<String, Object>();
		}
		try {
			if (getServlet(urlPat) != null) {
                log("Servlet overriden by " + servlet + ", for path:" + urlPat);
            }
			servlet.init(new ServeConfig(this, initParams, urlPat));
			registry.put(urlPat, servlet);
		} catch (ServletException e) { // 
			// it handles UnavailableException as well without an attempt to re-adding
			log("Problem initializing servlet, it won't be used: " + e);
		}
		return null;
	}
	
	/**
	 * 设置超级Servlet属性
	 * @author 刘虻
	 * 2008-6-28下午04:32:47
	 * @param servlet Servlet
	 */
	protected void setSuperServlet(Servlet servlet) {
		if (servlet!=null && servlet instanceof ASuperServlet) {
			//设置超级Servlet属性
			((ASuperServlet)servlet).setServ(this);
		}
	}


	/**
	 * 添加默认Servlet
	 * @author 刘虻
	 * 2008-6-28下午04:44:10
	 * @param throttles 配置文件路径
	 * @throws IOException 执行发生异常
	 */
	public void addDefaultServlets(String throttles) throws IOException {
		addServlet(
				"/"
				, FileServlet.newInstance(
						throttles
						, getServeParameter()));
	}

	/**
	 * 获取绑定地址
	 * @author 刘虻
	 * 2008-6-28下午05:00:36
	 * @return 绑定地址
	 */
	public String getBindAddress() {
		if (bindAddress==null) {
			bindAddress = 
				getServeParameter().getArgumentString(IGlobalVar.ARG_BINDADDRESS);
		}
		return bindAddress;
	}
	/**
	 * 启动服务器
	 * @author 刘虻
	 * 2008-6-28下午04:59:29
	 * @return 启动返回值
	 * @deprecated
	 */
	public int doServe() {
			
		try {
			//获取服务器Socket
			serverSocket = createServerSocket();
			if (getBindAddress().length()==0) {
				hostName = serverSocket.getInetAddress().getHostName();
			}else {
				hostName = InetAddress.getLocalHost().getHostName();
			}
		} catch (IOException e) {
			log("Server socket: " + e);
			return 1;
		}
		
		//是否启用SSL
		boolean enabledSsl = 
			getServeParameter().getArgumentBoolean(IGlobalVar.ART_ENABLED_SSL);
		if (enabledSsl) {
			try {
				//建立SSL连接
				sslServerSocket = createSSLServerSocket();
			}catch(Exception e) {
				log("SSL Server socket: " + e);
				return 1;
			}
		}
		//判断会话是否超时
		if (sessionTimeOut > 0) {
			ssclThread = new Thread(serverThreads, new Runnable() {
				@Override
                public void run() {
					while (running) {
						try {
							Thread.sleep(sessionTimeOut * 60 * 1000);
						} catch (InterruptedException ie) {
							if (running == false) {
                                break;
                            }
						}
						//获取会话主键迭代器
						Enumeration<String> e = sessions.keys();
						while (e.hasMoreElements()) {
							Object sid = e.nextElement();
							if (sid != null) {
								//获取会话对象
								Session as = (Session) sessions.get(sid);
								if (as!= null 
										&& (as.checkExpired() || !as.isValid())) { // log("sesion
									removeSession(as); //移除会话
								}
							}
						}
					}
				}
			}, "Session cleaner");
			ssclThread.setPriority(Thread.MIN_PRIORITY);
			ssclThread.start();
		} // else
		// sessionTimeOut = -sessionTimeOut;
		if (isKeepAlive()) {
			keepAliveCleaner = new KeepAliveCleaner();
			keepAliveCleaner.setTimeoutKeepAlive(timeoutKeepAlive);
			keepAliveCleaner.start();
		}
		if (sessions == null) {
			sessions = new HttpSessionContextImpl();
		}
		ListenAcceptThread httpdThread; //监听线程
		if(isNativeServ) {
			if (enabledSsl) {
				System.out.println("\n\n********************************************************************************************************\nStart SSL Native Web Server:[" 
			    + sslServerSocket + "]is listening.\n********************************************************************************************************\n\n");
				httpdThread = (new ListenAcceptThread(sslServerSocket,this));
			}else {
			      System.out.println("\n\n********************************************************************************************************\nStart Native Web Server:[" + serverSocket 
			                + "]is listening.\n********************************************************************************************************\n\n");
			      httpdThread =  (new ListenAcceptThread(serverSocket,this));
			}
		}else {
			if (enabledSsl) {
				System.out.println("\n\n(^_^)∠※ [" + new Date() + "] Start SSL httpd " + hostName + " - "
			   + sslServerSocket + " is listening. start used:("+(System.currentTimeMillis()-startTime)+")ms\n\n");
				httpdThread = (new ListenAcceptThread(sslServerSocket,this));
			}else {
			      System.out.println("\n\n(^_^)∠※ [" + new Date() + "] Start httpd " + hostName + " - " + serverSocket 
			                + " is listening. start used:("+(System.currentTimeMillis()-startTime)+")ms\n\n");
			      httpdThread =  (new ListenAcceptThread(serverSocket,this));
			}
		}
		httpdThread.start();
		
		//在启动服务后需要执行的命令行
		String executeCommand = 
				getServeParameter()
					.getArgumentString(
							IGlobalVar.ARG_AFTER_START_EXECUTE_COMMAND);
		if(executeCommand.length()>0) {
			try {
				//在启动后需要执行的命令
				Runtime.getRuntime().exec(executeCommand);
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
		try {
		    httpdThread.join();
		}catch(Exception e) {
			e.printStackTrace();
			return -1;
		}
		return 1;
	}

	/**
	 * 停止服务
	 * @author 刘虻
	 * 2008-6-28下午06:44:53
	 * @throws IOException 执行发生异常
	 */
	protected void notifyStop() throws IOException {
		running = false;
		serverSocket.close();
		serverSocket = null;
		sslServerSocket.close();
		sslServerSocket = null;
	}

	/**
	 * 终止所有线程
	 * @author 刘虻
	 * @deprecated
	 * 2008-6-28下午06:45:16
	 */
    protected void killAliveThreads() {
		serverThreads.interrupt();
		ThreadGroup tg = Thread.currentThread().getThreadGroup();
		while (tg.getParent() != null) {
            tg = tg.getParent();
        }
		int ac = tg.activeCount() + tg.activeGroupCount() + 10;

		Thread[] ts = new Thread[ac];
		ac = tg.enumerate(ts, true);
		if (ac == ts.length) {
            log("Destroy:interruptRunningProcesses: Not all threads will be stopped.");
        }
		// kill non daemon
		for (int i = 0; i < ac; i++) {
            if (ts[i].isDaemon() == false) {
                String tn = ts[i].getName();
                // System.err.println("Interrupting and kill " + tn);
                if (ts[i] == Thread.currentThread() || "Stop Monitor".equals(tn) || "ShutDownHook".equals(tn)
                        || "DestroyJavaVM".equals(tn) || (tn != null && tn.startsWith("AWT-"))) {
                    continue;
                }
                ts[i].interrupt();
                Thread.yield();
                if (ts[i].isAlive()) {
                    // System.out.println("Killing "+ts[i].getName());
                    try {
                        ts[i].stop();
                    } catch (Throwable t) {
                        if (t instanceof ThreadDeath) {
                            throw (Error) t;
                        }
                        // System.out.println("Ex: "+t);
                    }
                }
            }
        }
	}

	/**
	 * 停止服务
	 * @author 刘虻
	 * 2008-6-28下午05:10:32
	 * @throws IOException 执行发生异常
	 */
	public void stop() throws IOException {
		notifyStop();
	}
	
	
	/**
	 * 建立SSL安全连接
	 * @author 刘虻
	 * 2008-7-7下午06:44:23
	 * @return SSL安全连接
	 * @throws IOException 执行发生异常
	 */
	protected ServerSocket createSSLServerSocket() throws IOException {
		return (new SSLServerSocketFactory(this)).createSocket(getServeParameter());
	}
	

	/**
	 * 建立服务器连接
	 * @author 刘虻
	 * 2008-6-28下午05:42:49
	 * @return 服务器连接实例
	 * @throws IOException 执行发生异常
	 */
	protected ServerSocket createServerSocket() throws IOException {
		//Socket backlog
		int backlog = 
			getServeParameter()
				.getArgumentInt(IGlobalVar.ARG_BACKLOG);
		if (backlog<0) {
			backlog = 0;
		}
		//获取服务器监听端口
		int port = 
			getServeParameter()
				.getArgumentInt(IGlobalVar.ARG_PORT);
		if (port<1) {
			port = IGlobalVar.DEF_PORT;
		}
		InetAddress ia = null; //绑定地址类
		if (getBindAddress().length()>0) {
			try {
				ia = InetAddress.getByName(getBindAddress());
			} catch (Exception e) {}
		}
		try {
			if(ia!=null) {
				return new ServerSocket(port,backlog, ia);
			}else {
				return new ServerSocket(port);
			}
		}catch(IOException e2) {
			//构建错误信息
			StringBuffer errorMsg = new StringBuffer();
			
			errorMsg
				.append("\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n")
				.append("Create Socket Port:[")
				.append(port)
				.append("] Backlog:[")
				.append(backlog)
				.append("] BindAddress:[")
				.append(getBindAddress())
				.append("] Exception:[")
				.append(e2)
				.append("]\n")
				.append("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n\n");
			
			System.err.print(errorMsg);
			log(e2,errorMsg.toString());
			throw e2;
		}
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:38:12
	 */
    @Override
    public Servlet getServlet(String name) {
		try {
			return registry.get(name);
		} catch (NullPointerException npe) {
			return null;
		}
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午05:42:29
	 */
    @Override
    public Enumeration<Servlet> getServlets() {
		return registry.elements();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午05:42:35
	 */
    @Override
    public Enumeration<String> getServletNames() {
		return registry.keys();
	}

	/**
	 * 销毁所有的过滤器
	 * 刘虻
	 * 2010-7-29 上午09:08:05
	 * @deprecated
	 */
    @SuppressWarnings({ "rawtypes", "unchecked" })
	public synchronized void destroyAllFilter() {
		log("Entering destroyAllFilter()");
		// destroy filters
		final SEnumeration sEnum = new SEnumeration();
		sEnum.setAllElement(filterList);
		Runnable filterDestroyer = new Runnable() {
			@Override
            public void run() {
				((Filter) sEnum.nextElement()).destroy();				
			}			
		};
		while (sEnum.hasMoreElements()) {
			Thread destroyThread = new Thread(filterDestroyer, "Destroy Filter");
			destroyThread.start();
			try {
				destroyThread.join(10*1000);
			} catch (InterruptedException e) {
			}
			if (destroyThread.isAlive()) {
				destroyThread.stop();
			}
		}
		filterList = null;
	}

	/**
	 * 销毁当前所有的 Servlet
	 * @author 刘虻
	 * 2006-9-15下午12:14:08
	 * @deprecated
	 */
    public synchronized void destroyAllServlets() {
		log("Entering destroyAllServlets()");
		// destroy servlets
		final Enumeration<Servlet> en = registry.elements();
		Runnable servletDestroyer = new Runnable() {
			@Override
            public void run() {
			    en.nextElement().destroy();				
			}			
		};
		while (en.hasMoreElements()) {
			Thread destroyThread = new Thread(servletDestroyer, "Destroy Servlet");
			destroyThread.start();
			try {
				destroyThread.join(10*1000);
			} catch (InterruptedException e) {
			}
			if (destroyThread.isAlive()) {
				destroyThread.stop();
			}
		}
		//终止没被使用的servlet
		for(final Servlet servlet:getNoUseServletList()) {
			Runnable noUseServletDestroyer = new Runnable() {
				@Override
                public void run() {
					servlet.destroy();				
				}			
			};
			Thread destroyThread = new Thread(noUseServletDestroyer, "Destroy");
			destroyThread.start();
			try {
				destroyThread.join(10*1000);
			} catch (InterruptedException e) {
			}
			if (destroyThread.isAlive()) {
				destroyThread.stop();
			}
		}
		// clean access tree
		registry = new PathTreeDictionary();
	}


	/**
	 * 获取会话
	 * @author 刘虻
	 * 2008-6-28下午07:10:34
	 * @param id 会话主键
	 * @return 当前会话
	 */
	public Session getSession(String id) {
		return (Session) sessions.get(id);
	}

	
	/**
	 * 建立会话
	 * @author 刘虻
	 * 2008-6-28下午07:09:13
	 * @return 新的会话
	 */
	public HttpSession createSession() {
		//构造新的会话
		HttpSession result = 
			new Session(
					generateSessionId()
					, Math.abs(sessionTimeOut) * 60
					, this
					, sessions);
		sessions.put(result.getId(),result);
		
		//执行监听动作
		for(HttpSessionListener sessionListener:getSessionListenerList()) {
			if (sessionListener!=null) {
				sessionListener.sessionCreated(new HttpSessionEvent(result));
			}
		}
		return result;
	}

	/**
	 * 移除会话
	 * @author 刘虻
	 * 2008-6-28下午07:10:13
	 * @param id 会话主键
	 */
	public void removeSession(String id) {
		removeSession((Session)sessions.get(id));
	}
	
	
	/**
	 * 移除会话
	 * @author 刘虻
	 * 2008-6-28下午07:15:54
	 * @param session 会话
	 */
	protected void removeSession(Session session) {

		//执行监听动作
		for(HttpSessionListener sessionListener:getSessionListenerList()) {
			if (sessionListener!=null) {
				sessionListener.sessionDestroyed(new HttpSessionEvent(session));
			}
		}
		//从容器中除去指定会话
		Session as = (Session) sessions.remove(session.getId());
		if (as!=null && as.isValid()) {
			try {
				as.invalidate();
			} catch (IllegalStateException ise) {}
		}
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午03:21:37
	 */
	@Override
    public String getRealPath(String path) {
		if (path==null) {
			path = "";
		}
		if (contextPathLength>0 && path.startsWith(getContextPath())) {
			path = path.substring(contextPathLength);
		}
		return getServeParameter().getRealPath(path);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:38:34
	 */
	@Override
    public String getMimeType(String file) {
		return getServeParameter().getMimeType(file);
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:38:54
	 */
	@Override
    public String getServerInfo() {
		return IGlobalVar.SERVER_NAME + " " + IGlobalVar.SERVER_VERSION + " ("
				+ IGlobalVar.SERVER_URL + ")";
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:39:05
	 */
	@Override
    public Object getAttribute(String name) {
		return attributes.get(name);
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:39:11
	 */
	@Override
    public void removeAttribute(String name) {
		attributes.remove(name);
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:39:15
	 */
	@Override
    public void setAttribute(String name, Object object) {
		if (object != null) {
            attributes.put(name, object);
        } else {
            attributes.remove(name);
        }
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:39:22
	 */
	@Override
    public Enumeration<String> getAttributeNames() {
		return attributes.keys();
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:39:25
	 */
	@Override
    public ServletContext getContext(String uripath) {
		return this; // only root context supported
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:39:41
	 */
	@Override
    public int getMajorVersion() {
		return 2; // support 2.x
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:39:48
	 */
	@Override
    public int getMinorVersion() {
		return 5; // support 2.5
	}

	// 2.3

	/**
	 * Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path matches the supplied path argument.
	 * Paths indicating subdirectory paths end with a '/'. The returned paths are all relative to the root of the web application and have a leading '/'. For
	 * example, for a web application containing
	 * <p>
	 * /welcome.html <br>
	 * /catalog/index.html <br>
	 * /catalog/products.html <br>
	 * /catalog/offers/books.html <br>
	 * /catalog/offers/music.html <br>
	 * /customer/login.jsp <br>
	 * /WEB-INF/web.xml <br>
	 * /WEB-INF/classes/com.acme.OrderServlet.class,
	 * <p>
	 * getResourcePaths("/") returns {"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"} <br>
	 * getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}.
	 * <p>
	 * 
	 * @param the -
	 *            partial path used to match the resources, which must start with a /
	 * @return a Set containing the directory listing, or null if there are no resources in the web application whose path begins with the supplied path.
	 * @since Servlet 2.3
	 * 
	 */
	@Override
    public Set<String> getResourcePaths(String path) {
		String realPath = getRealPath(path);
		if (realPath != null) {
			String[] dir = new File(realPath).list();
			if (dir.length > 0) {
				HashSet<String> set = new HashSet<String>(dir.length);
				for (int i = 0; i < dir.length; i++) {
                    set.add(dir[i]);
                }
				return set;
			}
		}
		return null;
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-8下午07:23:10
	 */
	@Override
    public String getServletContextName() {
		return null;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-8下午07:23:15
	 */
	@Override
    public URL getResource(String path) throws MalformedURLException {
		if (path == null || path.length() == 0 || path.charAt(0) != '/') {
            throw new MalformedURLException("Path " + path + " is not in acceptable form.");
        }
		return new URL("file", "localhost", getRealPath(path));
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-7-8下午07:23:23
	 */
	@Override
    public InputStream getResourceAsStream(String path) {
		try {
			return getResource(path).openStream();
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:40:54
	 */
	@Override
    public RequestDispatcher getRequestDispatcher(String urlpath) {
		return this;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:41:02
	 */
	@Override
    public String getInitParameter(String param) {
		return null;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:41:05
	 */
	@Override
    public Enumeration<String> getInitParameterNames() {
		return null;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:41:12
	 */
	@Override
    public RequestDispatcher getNamedDispatcher(String name) {
		return this;
	}

	/**
	 * 获取新的会话主键
	 * @author 刘虻
	 * 2008-6-28下午06:41:14
	 * @return 新的会话主键
	 */
	protected synchronized String generateSessionId() {
		if (uniqer>99999999) {
			uniqer = 0;
		}
		return (new StringBuffer(getServerName()))
					.append("-")
					.append(System.currentTimeMillis())
					.append(uniqer++)
					.append("-")
					.append(Math.round(Math.random() * 1000))
					.toString();
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:41:17
	 */
	@Override
    public void forward(ServletRequest _request, ServletResponse _response) throws ServletException,
			java.io.IOException {
		throw new RuntimeException("forward() not supported");
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-6-28下午06:41:21
	 */
	@Override
    public void include(ServletRequest _request, ServletResponse _response) throws ServletException,
			java.io.IOException {
		throw new RuntimeException("include() not supported");
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2006-9-15上午09:50:02
	 */
	@Override
    public void log(String arg0) {
		log.log(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2006-9-15上午09:50:17
	 */
    @Override
    public void log(Exception arg0, String arg1) {
		log.log(arg0,arg1);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2006-9-15上午09:50:27
	 */
	@Override
    public void log(String arg0, Throwable arg1) {
		log.log(arg0,arg1);
	}
	
	/**
	 * 设置服务器名
	 * @author 刘虻
	 * 2008-6-28下午07:06:11
	 * @param serverName 服务器名
	 */
	public void setServerName(String serverName) {
		this.serverName = serverName;
	}
	
	/**
	 * 获取服务器名
	 * @author 刘虻
	 * 2008-6-28下午07:06:20
	 * @return 服务器名
	 */
	public String getServerName() {
		if (serverName==null) {
			serverName = "PX"+System.currentTimeMillis();
		}
		return serverName;
	}
	
	/**
	 * 获取会话主键名
	 * @author 刘虻
	 * 2008-6-28下午07:25:33
	 * @return 会话主键名
	 */
	public String getSessionCookieName() {
		return sessionCookieName;
	}
	
	/**
	 * 获取连接移除管理类
	 * @author 刘虻
	 * 2008-10-30下午03:52:10
	 * @return 连接移除管理类
	 */
	public KeepAliveCleaner getKeepAliveCleaner() {
		return keepAliveCleaner;
	}
	
	
	/**
	 * 获取线程管理器
	 * @author 刘虻
	 * 2008-10-30下午03:53:17
	 * @return 线程管理器
	 */
	public ThreadManager getThreadManager() {
		return threadManager;
	}
	
	/**
	 * 获取过滤器序列
	 * @author 刘虻
	 * 2008-6-29下午08:13:04
	 * @return 过滤器序列
	 */
	public List<Filter> getFilterList() {
		if (filterList==null) {
			filterList = new ArrayList<Filter>();
		}
		return filterList;
	}
	
	/**
	 * 获取会话监听器序列
	 * @author 刘虻
	 * 2008-6-29下午08:13:52
	 * @return 会话监听器序列
	 */
	public List<HttpSessionListener> getSessionListenerList() {
		if (sessionListenerList==null) {
			sessionListenerList = new ArrayList<HttpSessionListener>();
		}
		return sessionListenerList;
	}
	
	/**
	 * 获取获取只加载不使用的Servlet
	 * @author 刘虻
	 * 2008-7-28下午12:37:26
	 * @return 获取只加载不使用的Servlet
	 */
	protected ArrayList<Servlet> getNoUseServletList() {
		if (noUseServletList==null) {
			noUseServletList = new ArrayList<Servlet>();
		}
		return noUseServletList;
	}
	
	
	/**
	 * 获取虚拟路径
	 * @author 刘虻
	 * 2008-9-8下午03:43:30
	 * @return 虚拟路径
	 */
	@Override
    public String getContextPath() {
		if (contextPath==null) {
			contextPath = "";
		}
		return contextPath;
	}
	
	/**
	 * 获取虚拟路径长度
	 * @author 刘虻
	 * 2008-9-8下午03:54:17
	 * @return 虚拟路径长度
	 */
	public int getContextPathLength() {
		return contextPathLength;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-10-30下午03:46:42
	 */
	public String getHostName() {
		return hostName;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-10-30下午03:46:49
	 */
	public PathTreeDictionary getRegistry() {
		return registry;
	}

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2008-10-30下午06:57:02
	 */
	public boolean isRunning() {
		return running;
	}
	
	
	/**
	 * 获取默认显示文件字符串数组
	 * 
	 * @author 刘虻 2009-7-22下午03:27:40
	 * @return 默认显示文件字符串数组
	 */
	public String[] getWelcomeFilePages() {
		if (welcomePages == null) {
			if (serveParameter != null) {
				welcomePages = new String[serveParameter.getWelcomeFileList()
						.size()];
				serveParameter.getWelcomeFileList().toArray(welcomePages);
			}
			if (welcomePages == null || welcomePages.length < 1) {
				welcomePages = new String[0];
			}
		}
		return welcomePages;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#addFilter(java.lang.String, java.lang.String)
	 */
	@Override
	public Dynamic addFilter(String arg0, String arg1) {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#addFilter(java.lang.String, javax.servlet.Filter)
	 */
	@Override
	public Dynamic addFilter(String arg0, Filter arg1) {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#addFilter(java.lang.String, java.lang.Class)
	 */
	@Override
	public Dynamic addFilter(String arg0, Class<? extends Filter> arg1) {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#addListener(java.lang.String)
	 */
	@Override
	public void addListener(String arg0) {}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#addListener(java.util.EventListener)
	 */
	@Override
	public <T extends EventListener> void addListener(T arg0) {}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#addListener(java.lang.Class)
	 */
	@Override
	public void addListener(Class<? extends EventListener> arg0) {}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#addServlet(java.lang.String, java.lang.Class)
	 */
	@Override
	public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, Class<? extends Servlet> arg1) {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#createFilter(java.lang.Class)
	 */
	@Override
	public <T extends Filter> T createFilter(Class<T> arg0) throws ServletException {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#createListener(java.lang.Class)
	 */
	@Override
	public <T extends EventListener> T createListener(Class<T> arg0) throws ServletException {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#createServlet(java.lang.Class)
	 */
	@Override
	public <T extends Servlet> T createServlet(Class<T> arg0) throws ServletException {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#declareRoles(java.lang.String[])
	 */
	@Override
	public void declareRoles(String... arg0) {}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getClassLoader()
	 */
	@Override
	public ClassLoader getClassLoader() {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getDefaultSessionTrackingModes()
	 */
	@Override
	public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getEffectiveMajorVersion()
	 */
	@Override
	public int getEffectiveMajorVersion() {
		return 0;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getEffectiveMinorVersion()
	 */
	@Override
	public int getEffectiveMinorVersion() {
		return 0;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getEffectiveSessionTrackingModes()
	 */
	@Override
	public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getFilterRegistration(java.lang.String)
	 */
	@Override
	public FilterRegistration getFilterRegistration(String arg0) {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getFilterRegistrations()
	 */
	@Override
	public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getJspConfigDescriptor()
	 */
	@Override
	public JspConfigDescriptor getJspConfigDescriptor() {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getServletRegistration(java.lang.String)
	 */
	@Override
	public ServletRegistration getServletRegistration(String arg0) {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getServletRegistrations()
	 */
	@Override
	public Map<String, ? extends ServletRegistration> getServletRegistrations() {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#getSessionCookieConfig()
	 */
	@Override
	public SessionCookieConfig getSessionCookieConfig() {
		return null;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#setInitParameter(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean setInitParameter(String arg0, String arg1) {
		return false;
	}

	/* （非 Javadoc）
	 * @see javax.servlet.ServletContext#setSessionTrackingModes(java.util.Set)
	 */
	@Override
	public void setSessionTrackingModes(Set<SessionTrackingMode> arg0)
			throws IllegalStateException, IllegalArgumentException {}

  @Override
  public javax.servlet.ServletRegistration.Dynamic addJspFile(String arg0, String arg1) {
    return null;
  }

  @Override
  public String getRequestCharacterEncoding() {
    return null;
  }

  @Override
  public String getResponseCharacterEncoding() {
    return null;
  }

  @Override
  public int getSessionTimeout() {
    return 0;
  }

  @Override
  public String getVirtualServerName() {
    return null;
  }

  @Override
  public void setRequestCharacterEncoding(String arg0) {}

  @Override
  public void setResponseCharacterEncoding(String arg0) {}

  @Override
  public void setSessionTimeout(int arg0) {}
}